#ifndef _R_String_h
#define _R_String_h

#include <Ape/Object.h>
#include <Ape/Cloneable.h>

namespace Ape {
	namespace Collections {
		class StringList;
	}
	
	namespace String_Util {
		size_t wcstr_len (const wchar_t* wcstr, size_t maxLen = -1);
		size_t wcstr_calc_allocate (size_t iAtLeast, int sizeOfElement = 1);
		bool wchar2uglychars (wchar_t wch, char* chs);
		wchar_t char2wchar (char ch);
		
		size_t cstr_len (const char* cstr, size_t maxLen = -1);
	}
	
	/**
		Represents a character (wrapper for wchar_t)
		@author Roman Gafiyatullin
	*/
	class Character
				: public Object
	{
		TYPE_NAME ("Ape::Character")
		CLONEABLE (Character)
		friend bool operator == (const Character& c1, const Character& c2);
		friend bool operator > (const Character& c1, const Character& c2);
		friend bool operator < (const Character& c1, const Character& c2);
		friend bool operator >= (const Character& c1, const Character& c2);
		friend bool operator <= (const Character& c1, const Character& c2);
	private:
		wchar_t m_WChar;
	public:
		Character();
		Character (wchar_t wchar);
		Character (const Character& other);
		
		virtual ~Character();
		
		/**
			@return system-specific wchar_t representation of the character
		*/
		wchar_t C() const;
		
		// It causes a lot of ambiguity
		//operator wchar_t() const;
	};
	
	/**
		unicode string (string of wchar_t)
		
		@author Roman Gafiyatullin
	*/
	class String
				: public Object
	{
		TYPE_NAME ("Ape::String")
		CLONEABLE (String)
		
		friend const String operator + (const String& s1, const String& s2);
		friend bool operator == (const String& s1, const String& s2);
		friend bool operator > (const String& s1, const String& s2);
		friend bool operator < (const String& s1, const String& s2);
		friend bool operator >= (const String& s1, const String& s2);
		friend bool operator <= (const String& s1, const String& s2);
	private:
	
		/**
			pointer to the array of wchar_t's
		*/
		wchar_t* m_WCStr;
		/**
			our buffer is not null-terminated - we need to store length separately
		*/
		size_t m_Length;
		/**
			we allocate eq-or-more than the real length of the string in order not to frag memory too much
		*/
		size_t m_Allocated;
		
		void Allocate (size_t iCount);
	public:
		/**
			assignment via eq-sign?
		*/
		String& operator = (const String& other);
		
		virtual void _Dump (bool verbose = false) const;
		
		virtual const String ToString() const;
		
		/**
			create NULL string
		*/
		String();
		/**
			copy ctor
		*/
		String (const String& other);
		virtual ~String();
		
		/**
			initialize from null-terminated L-string
			@param wcstr wchar_t-string
		*/
		String (const wchar_t* wcstr);
		
		/**
			initialize from wchar_t* with given length
			@param wcstr wchar_t-string
		*/
		String (const wchar_t* wcstr, size_t length);
		
		/**
			initialize from single-byted null-terminated string
			@param cstr s-byte string
		*/
		String (const char* cstr);
		
		/**
			@return internal buffer
		*/
		const wchar_t* ToWChars() const;
		/**
			@param pBuff [out] creates buffer with Latin-1 string and puts pointer over it
			@warning when pBuff is not NULL it will try to be freed
			@return true when some of the chars are not latin-1
		*/
		bool ToLatin1 (char** pBuff) const;
		
		/**
			@return Length of the string
		*/
		size_t get_Length() const;
		/**	@return size of the buffer allocated for the string
		*/
		size_t get_Allocated() const;
		
		/**
			@param iPos zero-based position of the character
			@return character under the iPos (as Ape::Character)
			@throw EIndexOutOfRange when iPos >= Length
			
		*/
		Character At (size_t iPos) const;
		/**
			@param iPos zero-based position of the character
			@return character under the iPos (as wchar_t)
			@throw EIndexOutOfRange when iPos >= Length
		*/
		wchar_t WcharAt (size_t iPos) const;
		
		/**
			@param needle character to find
			@param from zero-based position to begin search
			@return zero-based position on success and -1 on failure
		*/
		int IndexOf (const Character& needle, size_t from = 0) const;
		int Find (const String& needle, size_t from = 0) const;
		const String Substr (size_t length, size_t from = 0) const;
		const String Substring (int from, int to = -1) const;
		
		void Split (const Character& splitter, Collections::StringList& result, int maxParts = -1) const;
		void Split (const String& splitter, Collections::StringList& result, int maxParts = -1) const;
		
		String Replace (const String& what, const String& with) const;
		
		bool IsEmpty() const;
		
		operator const wchar_t* () const;
	};
	
	const String operator + (const String& s1, const String& s2);
	bool operator == (const String& s1, const String& s2);
	bool operator != (const String& s1, const String& s2);
	bool operator > (const String& s1, const String& s2);
	bool operator < (const String& s1, const String& s2);
	bool operator >= (const String& s1, const String& s2);
	bool operator <= (const String& s1, const String& s2);
	
	
	bool operator == (const Character& c1, const Character& c2);
	bool operator != (const Character& c1, const Character& c2);
	bool operator > (const Character& c1, const Character& c2);
	bool operator < (const Character& c1, const Character& c2);
	bool operator >= (const Character& c1, const Character& c2);
	bool operator <= (const Character& c1, const Character& c2);
	
}

#endif // _R_String_h
